package jmine.tec.hydra.provider;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import jmine.tec.hydra.api.CallActivationAction;
import jmine.tec.hydra.api.DecodeMessageAction;
import jmine.tec.hydra.api.EncodeMessageAction;
import jmine.tec.hydra.api.FailedServicePageAction;
import jmine.tec.hydra.api.HydraAction;
import jmine.tec.hydra.api.HydraMessage;
import jmine.tec.hydra.api.HydraProvider;
import jmine.tec.hydra.api.HydraRequest;
import jmine.tec.hydra.api.HydraSpecification;
import jmine.tec.hydra.api.MessageActivationAction;
import jmine.tec.hydra.api.MessageDirection;
import jmine.tec.hydra.api.ReceiveMessageAction;
import jmine.tec.hydra.api.SendMessageAction;
import jmine.tec.hydra.dao.HydraSpecificationDAO;
import jmine.tec.hydra.domain.HydraRequestImpl;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.domain.actions.DefaultCallActivationAction;
import jmine.tec.hydra.domain.actions.DefaultDecodeMessageAction;
import jmine.tec.hydra.domain.actions.DefaultEncodeMessageAction;
import jmine.tec.hydra.domain.actions.DefaultFailedServicePageAction;
import jmine.tec.hydra.domain.actions.DefaultMessageActivationAction;
import jmine.tec.hydra.domain.actions.DefaultReceiveMessageAction;
import jmine.tec.hydra.domain.actions.DefaultSendMessageAction;
import jmine.tec.hydra.domain.enumx.HydraRequestType;
import jmine.tec.hydra.domain.message.HydraMessageImpl;
import bancosys.tec.persist.controller.PersistenceEnabledController;
import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.utils.date.Timestamp;

/**
 * Implementação default da interface HydraProvider
 * 
 * @author lundberg
 */
public class DefaultHydraProvider implements HydraProvider {

    private final Map<Class<? extends HydraAction>, Class<? extends HydraAction>> actionMap =
            new HashMap<Class<? extends HydraAction>, Class<? extends HydraAction>>();

    private PersistenceEnabledController controller;

    /**
     * Construtor
     */
    public DefaultHydraProvider() {
        this.actionMap.put(CallActivationAction.class, DefaultCallActivationAction.class);
        this.actionMap.put(DecodeMessageAction.class, DefaultDecodeMessageAction.class);
        this.actionMap.put(EncodeMessageAction.class, DefaultEncodeMessageAction.class);
        this.actionMap.put(FailedServicePageAction.class, DefaultFailedServicePageAction.class);
        this.actionMap.put(MessageActivationAction.class, DefaultMessageActivationAction.class);
        this.actionMap.put(ReceiveMessageAction.class, DefaultReceiveMessageAction.class);
        this.actionMap.put(SendMessageAction.class, DefaultSendMessageAction.class);
    }

    /**
     * {@inheritDoc}
     */
    public <A extends HydraAction> A createAction(Class<A> action) {
        Class<? extends A> actionClass = this.actionMap.get(action).asSubclass(action);
        BaseDAO<? extends A> dao = this.controller.getDAOFactory().getGenericDAO(actionClass);
        return dao.createBean();
    }

    /**
     * {@inheritDoc}
     */
    public HydraMessage createMessage(HydraRequest request, MessageDirection direction, InputStream body, Map<String, String> properties) {
        BaseDAO<HydraMessageImpl> dao = this.controller.getDAOFactory().getGenericDAO(HydraMessageImpl.class);

        HydraMessageImpl message = dao.createBean();
        message.setBody(body);
        message.setDirection(direction);
        message.setProperties(properties);
        message.setTimestamp(new Timestamp());

        return message;
    }

    /**
     * {@inheritDoc}
     */
    public HydraRequest createRequest(HydraRequestType requestType) {
        BaseDAO<HydraRequestImpl> dao = this.controller.getDAOFactory().getGenericDAO(HydraRequestImpl.class);
        HydraRequestImpl request = dao.createBean();
        request.setRequestType(requestType);
        return request;
    }

    /**
     * {@inheritDoc}
     */
    public HydraRequest createRequest(HydraRequestType requestType, HydraSpecification specification) {
        BaseDAO<HydraRequestImpl> dao = this.controller.getDAOFactory().getGenericDAO(HydraRequestImpl.class);
        HydraRequestImpl request = dao.createBean();
        request.setRequestType(requestType);
        request.setSpecification(specification);
        request.setSystem(specification.getSystem());
        return request;
    }

    /**
     * {@inheritDoc}
     */
    public HydraSpecification findSpecification(HydraSystem system, String action) throws BeanNotFoundException {
        HydraSpecificationDAO dao = this.controller.getDAOFactory().getDAOByClass(HydraSpecificationDAO.class);
        return dao.findByActionSystem(system, action);
    }

    /**
     * @return the controller
     */
    public PersistenceEnabledController getController() {
        return this.controller;
    }

    /**
     * @param controller the controller to set
     */
    public void setController(PersistenceEnabledController controller) {
        this.controller = controller;
    }
}
